﻿using System;
using System.Globalization;
using System.Windows.Automation;
using ProdControls.Interfaces;
using ProdControls.UIAPatterns;
using ProdControls.Verification;
using ProdLogging;

namespace ProdControls.Bridges
{
    internal static class RangeValueBridge
    {
        /// <summary>
        ///   Gets the value.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <returns> Current value of the control </returns>
        public static double GetValueHook(this IRangeValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetValue(control);
            }
            catch (InvalidOperationException)
            {
                return NativeGetValue(control);
            }
        }

        private static double NativeGetValue(BaseProdControl control)
        {
            if (control.UIAElement.Current.ControlType == ControlType.Spinner)
                return ProdSliderNative.GetValueNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);

            return ProdSliderNative.GetValueNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
        }

        private static double UiaGetValue(BaseProdControl control)
        {
            double retVal = RangeValuePatternHelper.GetValue(control.UIAElement);
            LogController.ReceiveLogMessage(new LogMessage(retVal.ToString(CultureInfo.InvariantCulture)));

            return retVal;
        }

        /// <summary>
        ///   Sets the value of the specified control.
        /// </summary>
        /// <param name="extension"> The extension interface </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="value"> The value to set control to. </param>
        public static void SetValueHook(this IRangeValue extension, BaseProdControl control, double value)
        {
            try
            {
                UiaSetValue(control, value);
            }
            catch (InvalidOperationException)
            {
                NativeSetValue(control, value);
            }
        }

        private static void NativeSetValue(BaseProdControl control, double value)
        {
            if (control.UIAElement.Current.ControlType == ControlType.Spinner)
                ProdSpinnerNative.SetValueNative((IntPtr) control.UIAElement.Current.NativeWindowHandle, value);

            ProdSliderNative.SetValueNative((IntPtr) control.UIAElement.Current.NativeWindowHandle, value);
        }

        private static void UiaSetValue(BaseProdControl control, double value)
        {
            LogController.ReceiveLogMessage(new LogMessage(value.ToString(CultureInfo.InvariantCulture)));

            AutomationEventVerifier.Register(new EventRegistrationMessage(control, RangeValuePattern.ValueProperty));
            RangeValuePatternHelper.SetValue(control.UIAElement, value);
        }

        /// <summary>
        ///   Gets the maximum value of the control.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <returns> The maximum value of the control </returns>
        public static double GetMaxValueHook(this IRangeValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetMaxValue(control);
            }
            catch (InvalidOperationException)
            {
                return NativeGetMaxValue(control);
            }
        }

        private static double NativeGetMaxValue(BaseProdControl control)
        {
            if (control.UIAElement.Current.ControlType == ControlType.Spinner)
                return ProdSpinnerNative.GetMaximumNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);

            return
                (double) ProdSliderNative.GetSmallChangeNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
        }

        private static double UiaGetMaxValue(BaseProdControl control)
        {
            double retVal = RangeValuePatternHelper.GetMaximum(control.UIAElement);
            LogController.ReceiveLogMessage(new LogMessage(retVal.ToString(CultureInfo.InvariantCulture)));
            return retVal;
        }

        /// <summary>
        ///   Gets the minimum value of the control.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <returns> The minimum value of the control. </returns>
        public static double GetMinValueHook(this IRangeValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetMinValue(control);
            }
            catch (InvalidOperationException)
            {
                return NativeGetMinValue(control);
            }
        }

        private static double NativeGetMinValue(BaseProdControl control)
        {
            if (control.UIAElement.Current.ControlType == ControlType.Spinner)
                return ProdSpinnerNative.GetMinimumNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);

            return ProdSliderNative.GetMinimumNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
        }

        private static double UiaGetMinValue(BaseProdControl control)
        {
            double retVal = RangeValuePatternHelper.GetMinimum(control.UIAElement);
            LogController.ReceiveLogMessage(new LogMessage(retVal.ToString(CultureInfo.InvariantCulture)));
            return retVal;
        }

        /// <summary>
        ///   Gets the large change value for the control.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <returns> A number indicating the increment of a large change </returns>
        public static double GetLargeChangeHook(this IRangeValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetLargeChange(control);
            }
            catch (InvalidOperationException)
            {
                return NativeGetLargeChange(control);
            }
        }

        private static double NativeGetLargeChange(BaseProdControl control)
        {
            return
                (double) ProdSliderNative.GetLargeChangeNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
        }

        private static double UiaGetLargeChange(BaseProdControl control)
        {
            double retVal = RangeValuePatternHelper.GetLargeChange(control.UIAElement);
            LogController.ReceiveLogMessage(new LogMessage(retVal.ToString(CultureInfo.InvariantCulture)));
            return retVal;
        }

        /// <summary>
        ///   Gets the small change value for the control.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <returns> A number indicating the increment of a small change </returns>
        public static double GetSmallChangeHook(this IRangeValue extension, BaseProdControl control)
        {
            try
            {
                return UiaGetSmallChange(control);
            }
            catch (InvalidOperationException)
            {
                return NativeGetSmallChange(control);
            }
        }

        private static double NativeGetSmallChange(BaseProdControl control)
        {
            return
                (double) ProdSliderNative.GetSmallChangeNative((IntPtr) control.UIAElement.Current.NativeWindowHandle);
        }

        private static double UiaGetSmallChange(BaseProdControl control)
        {
            double retVal = RangeValuePatternHelper.GetSmallChange(control.UIAElement);
            LogController.ReceiveLogMessage(new LogMessage(retVal.ToString(CultureInfo.InvariantCulture)));
            return retVal;
        }

        public static bool IsReadOnlyHook(this IRangeValue extension, BaseProdControl control)
        {
            return UiaIsReadOnly(control);
        }

        private static bool UiaIsReadOnly(BaseProdControl control)
        {
            return RangeValuePatternHelper.IsReadOnly(control.UIAElement);
        }
    }
}